// ==UserScript==
// @name					Popup Search
// @name:zh					Popup Search: 快捷搜索
// @author					lkytal
// @namespace				Lkytal
// @version					5.2.3
// @icon					https://github.com/lkytal/GM/raw/master/icons/search.png
// @homepage				https://lkytal.github.io/
// @homepageURL				https://lkytal.github.io/GM
// @description				Popup search box and translate button (etc) for selected texts
// @description:zh			为选中文字弹出搜索和翻译的快捷按钮
// @license					AGPL
// @include					*
// @exclude					*/test/*.html*
// @exclude					http://acid3.acidtests.org/*
// @exclude					http://www.acfun.tv/*
// @exclude					http://www.sf-express.com/*
// @exclude					http://furk.net/*
// @connect					google.com
// @connect					google.cn
// @grant					GM_xmlhttpRequest
// @grant					GM_addStyle
// @grant					GM_openInTab
// @grant					GM_setClipboard
// @grant					GM_download
// @grant					GM_getValue
// @grant					GM_setValue
// @grant					GM_registerMenuCommand
// @grant					GM_info
// @run-at					document-end
// @inject-into				auto
// @require					https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.6.0.min.js
// @connect					google.com
// @connect					google.cn
// @connect					caiyunai.com
// @connect					deepl.com
// @charset					UTF-8
// @supportURL				https://github.com/lkytal/GM/issues
// @updateURL				https://git.oschina.net/coldfire/GM/raw/master/meta/popsearch.meta.js
// @downloadURL				https://git.oschina.net/coldfire/GM/raw/master/popsearch.user.js
// ==/UserScript==

"use strict";
;
var CopyText,
    GetOpt,
    GetTextboxSelection,
    InTextBox,
    OnEngine,
    OpenSet,
    OpenUrl,
    PopupInit,
    PopupLoad,
    ReadOpt,
    SaveOpt,
    SettingWin,
    ShowBar,
    UpdateLog,
    UpdateNotified,
    addAdditionalCSS,
    addCSS,
    ajaxError,
    doHideBar,
    doRequest,
    eventFromTextbox,
    fixPos,
    getLastRange,
    get_selection_offsets,
    hideBar,
    isChrome,
    log,
    needPrefix,
    onCopy,
    onTranslate,
    parseTranslationCaiyun,
    parseTranslationDeepl,
    parseTranslationGoogle,
    popData,
    hasProp = {}.hasOwnProperty;

window.$ = window.jQuery = jQuery.noConflict(true);

popData = {
  count: 0,
  mouseIn: 0,
  bTrans: 0,
  additionalCSSLoaded: 0,
  codeVersion: 8,
  text: "",
  mousedownEvent: null,
  fadeEvent: [],
  icons: {
    handianIcon: "https://www.zdic.net/favicon.ico",
    baiduIcon: "",
    bingIcon: "",
    translateIcon: "",
    googleIcon: "",
    linkIcon: "",
    taobaoIcon: "",
    yahooIcon: "",
    wikiIcon: "",
    jdIcon: "",
    eBayIcon: "",
    doubanIcon: "",
    amazonIcon: "",
    youkuIcon: "",
    youtubeIcon: "",
    tiebaIcon: "",
    inSiteIcon: '',
    settingIcon: "",
    tipDown: "",
    tipUp: "",
    pending: "",
    copyIcon: ""
  },
  optionList: [{
    id: "AutoCopy_st",
    text: "自动复制选中文字 / Auto copy selections",
    defaultValue: 0
  }, {
    id: "AutoCopy_tbox_st",
    text: "自动复制在文本框也生效 / Enable Autocopy in textboxes",
    defaultValue: 0
  }, {
    id: "Textbox_st",
    text: "不在文本框内显示 / Ignore selections in textboxes",
    defaultValue: 0
  }, {
    id: "Fade_st",
    text: "超时自动隐藏 / Hide after timeout",
    defaultValue: 1
  }, {
    id: "Click_st",
    text: "点击页面不隐藏 / Don't Hide on click",
    defaultValue: 0
  }, {
    id: "Tab_st",
    text: "新标签页打开 / Open in new tabs",
    defaultValue: 1
  }, {
    id: "Focus_st",
    text: "前台标签页打开 / Force foreground tabs",
    defaultValue: 1
  }, {
    id: "Iframe_st",
    text: "在Iframe中显示/ Activate in iframes",
    defaultValue: 1
  }, {
    id: "Dis_st",
    text: "显示于文字上方 / Display above selection",
    defaultValue: 1
  }, {
    id: "Ctrl_st",
    text: "仅按下Ctrl时显示 / Only when ctrl pressed",
    defaultValue: 0
  }, {
    id: "userEngine_st",
    text: "自定义引擎 / Enable Customize",
    defaultValue: 0
  }],
  userEngines: [],
  defaultEngines: [{
    id: "UserEngine",
    title: "Example of User Engine",
    description: "自定义引擎示例 / Example of user engine",
    src: "https://github.com/lkytal/GM/raw/master/icons/atom.png",
    href: "https://www.google.com/search?newwindow=1&safe=off&q=${text}"
  }, {
    id: "UserEngine_dataURL",
    title: "Example Engine use dataURL",
    description: "DataURL引擎示例 / Example Engine use dataURL",
    src: "",
    href: "https://www.google.com/search?q=${text}%20site:${domain}"
  }, {
    id: "UserEngine_function",
    title: "Example of User Engine use function",
    description: "function自定义引擎示例 / Example of user engine use function",
    src: "https://github.com/lkytal/GM/raw/master/icons/atom.png",
    function: "alert('action on ' + domain); OpenUrl(text);"
  }]
};

popData.engines = [{
  id: "Trans_st",
  title: "Translate",
  description: "Google翻译 / Translate selection (Google)",
  defaultState: 1,
  src: popData.icons.translateIcon,
  action: function () {
    return onTranslate('google');
  }
}, {
  // {
  // 	id: "Trans_caiyun_st"
  // 	title: "Translate (Caiyun)"
  // 	description: "彩云小译翻译文本 / Translate selection (Caiyun)"
  // 	defaultState: 0
  // 	src: popData.icons.translateIcon
  // 	action: () -> onTranslate('caiyun')
  // },
  // {
  // 	id: "Trans_deepl_st"
  // 	title: "Translate (Deepl)"
  // 	description: "Deepl翻译文本 / Translate selection (Deepl)"
  // 	defaultState: 0
  // 	src: popData.icons.translateIcon
  // 	action: () -> onTranslate('deepl')
  // },
  id: "Copy_st",
  title: "Copy",
  description: "复制文本 / Copy selection",
  defaultState: 1,
  src: popData.icons.copyIcon,
  action: function () {
    return onCopy();
  }
}, {
  id: "Setting_st",
  title: "Open Setting",
  description: "Popup search 选项 / Open Setting",
  defaultState: 1,
  src: popData.icons.settingIcon,
  action: function () {
    return OpenSet();
  }
}, {
  id: "Open_st",
  title: "Open As Url",
  description: "选中文本视作链接打开 / Open selection as url",
  defaultState: 0,
  src: popData.icons.linkIcon,
  href: '${rawText}'
}, {
  id: "Site_st",
  title: "Search Current Website",
  description: "在当前网站内搜索 / Search in current website",
  defaultState: 1,
  src: popData.icons.inSiteIcon,
  href: 'https://www.google.com/search?newwindow=1&safe=off&q=${text}%20site:${domain}'
}, {
  id: "amazon_st",
  title: "Search with Amazon",
  description: "搜索亚马逊/ Search with Amazon",
  defaultState: 0,
  src: popData.icons.amazonIcon,
  href: 'https://www.amazon.com/s?k=${text}'
}, {
  id: "Bing_st",
  title: "Search with Bing",
  description: "必应搜索 / Search with Bing",
  defaultState: 1,
  src: popData.icons.bingIcon,
  href: 'https://bing.com/search?q=${text}&form=MOZSBR'
}, {
  id: "Baidu_st",
  title: "Search with Baidu",
  description: "百度搜索 / Search with Baidu",
  defaultState: 0,
  src: popData.icons.baiduIcon,
  href: 'https://www.baidu.com/s?wd=${text}&ie=utf-8'
}, {
  "id": "Baidu_fy_st",
  "title": "Baidu Page Translation",
  "description": "百度页面翻译 / Baidu Page Translation",
  "src": "https://fanyi.baidu.com/favicon.ico",
  "href": "http://fanyi.baidu.com/transpage?query=${url}&source=url&ie=utf8&from=auto&to=zh&render=1"
}, {
  id: "Yahoo_st",
  title: "Search with Yahoo",
  description: "雅虎搜索 / Search with Yahoo",
  defaultState: 0,
  src: popData.icons.yahooIcon,
  href: 'https://search.yahoo.com/search;?p=${text}&ei=UTF-8'
}, {
  id: "Taobao_st",
  title: "Search with Taobao",
  description: "搜索淘宝 / Search with Taobao",
  defaultState: 0,
  src: popData.icons.taobaoIcon,
  href: 'https://s.taobao.com/search?q=${text}'
}, {
  id: "Tieba_st",
  title: "Search in Tieba",
  description: "搜索贴吧 / Search with Tieba",
  defaultState: 0,
  src: popData.icons.tiebaIcon,
  href: 'http://tieba.baidu.com/f/search/res?ie=utf-8&qw=${text}'
}, {
  id: "youtube_st",
  title: "Search with Youtube",
  description: "搜索Youtube / Search with Youtube",
  defaultState: 1,
  src: popData.icons.youtubeIcon,
  href: 'https://www.youtube.com/results?search_query=${text}'
}, {
  id: "youku_st",
  title: "Search with Youku",
  description: "搜索优酷 / Search with Youku",
  defaultState: 0,
  src: popData.icons.youkuIcon,
  href: 'http://www.soku.com/search_video/q_${text}'
}, {
  id: "eBay_st",
  title: "Search with eBay",
  description: "搜索eBay / Search with eBay",
  defaultState: 0,
  src: popData.icons.eBayIcon,
  href: 'http://www.ebay.com/sch/i.html?_nkw=${text}&_sacat=0'
}, {
  id: "douban_st",
  title: "Search with Douban",
  description: "搜索豆瓣电影 / Search with Douban Movie",
  defaultState: 0,
  src: popData.icons.doubanIcon,
  href: 'https://movie.douban.com/subject_search?search_text=${text}'
}, {
  id: "jd_st",
  title: "Search with JD",
  description: "搜索京东 / Search with JD",
  defaultState: 0,
  src: popData.icons.jdIcon,
  href: 'https://search.jd.com/Search?keyword=${text}&enc=utf-8'
}, {
  id: "handian_st",
  title: "Search with Handian",
  description: "汉典搜索 / Search with Handian",
  defaultState: 0,
  src: popData.icons.handianIcon,
  href: 'https://www.zdic.net/hans/${text}'
}, {
  id: "Google_st",
  title: "Search with Google",
  description: "谷歌搜索 / Search with Google",
  defaultState: 1,
  src: popData.icons.googleIcon,
  href: 'https://www.google.com/search?newwindow=1&safe=off&q=${text}'
}, {
  id: "Wiki_st",
  title: "Search with Wiki",
  description: "搜索维基百科 / Search with Wikipedia",
  defaultState: 1,
  src: popData.icons.wikiIcon,
  href: 'https://wikipedia.org/w/index.php?search=${text}'
}];

log = function (msg) {
  popData.count += 1;
  return console.log(`Popup Msg ${popData.count} : ${msg}`);
};

isChrome = function () {
  return navigator.userAgent.indexOf("Chrome") > -1;
};

fixPos = function (sel, e) {
  var eventLeft, eventTop, fix, m_left, offsetLeft, offsetTop, offsets;
  offsets = get_selection_offsets(sel, e);
  offsetTop = offsets[0];
  offsetLeft = offsets[1];
  if (e != null) {
    eventTop = e.pageY;
    eventLeft = e.pageX;
    //log offsetTop + " : " + offsetLeft + " <==> " + eventTop + " : " + eventLeft
    if (Math.abs(offsetTop - eventTop) > 50) {
      offsetTop = eventTop - 10;
    } else {
      offsetTop = Math.min(eventTop - 10, offsetTop);
    }
    if (Math.abs(offsetLeft - eventLeft) > 50) {
      //translate
      offsetLeft = eventLeft + 10;
    }
  } else {
    $('#showUpBody').css('margin-left', '60px');
  }
  if (GetOpt('Dis_st')) {
    //UpSide
    offsetTop = offsetTop - 4 - $('#ShowUpBox').height();
    if (offsetTop - document.documentElement.scrollTop < 40) {
      offsetTop = document.documentElement.scrollTop + 40;
    }
  } else {
    offsetTop += 1.1 * offsets[2];
  }
  m_left = $('#ShowUpBox').width();
  fix = 0;
  if (offsetLeft - m_left < 4) {
    fix = 4 - offsetLeft + m_left;
  }
  $('#ShowUpBox').css("top", offsetTop + "px").css("left", offsetLeft - m_left + fix + "px");
  return $('#popupTip').css('margin-left', m_left - 20 - fix);
};

PopupInit = function () {
  var $DivBox, $icon, EngineList, engine, j, k, l, len, len1, len2, ref, ref1, ref2;
  $('#ShowUpBox').remove();
  EngineList = "";
  ref = popData.engines;
  for (j = 0, len = ref.length; j < len; j++) {
    engine = ref[j];
    EngineList += `<a id='${engine.id}Icon' class='engine'><img title='${engine.title}' src='${engine.src}' /></a>`;
  }
  if (GetOpt("userEngine_st")) {
    ref1 = popData.userEngines;
    for (k = 0, len1 = ref1.length; k < len1; k++) {
      engine = ref1[k];
      EngineList += `<a id='${engine.id}Icon' class='userEngine'><img title='${engine.title}' src='${engine.src}' /></a>`;
    }
  }
  $('html').append(`<span id=\"ShowUpBox\"> <span id=\"showUpBody\"> <span id=\"popupWrapper\"> ${EngineList} </span> <span id=\"transPanel\" /> </span> </span>`);
  $DivBox = $('#ShowUpBox');
  $DivBox.hide();
  $DivBox.on("click dblclick mousedown mouseup contextmenu", function (event) {
    return event.stopPropagation();
  });
  $('#transPanel').on("mouseup contextmenu", function (event) {
    return event.stopPropagation();
  });
  $DivBox.hover(function () {
    $(this).fadeTo(150, 1);
    return popData.mouseIn = 1;
  }, function () {
    if (popData.bTrans === 0 && $(this).is(":visible") && $(this).attr("opacity") === 1) {
      $(this).fadeTo(300, 0.7);
      clearTimeout(popData.timer);
      popData.timer = setTimeout(TimeOutHide, 6000);
    }
    return popData.mouseIn = 0;
  });
  $('#showUpBody').on("mouseup", function (event) {
    if (event.which === 3) {
      CopyText();
      hideBar(100);
      return false;
    } else if (event.which === 2) {
      GM_openInTab(document.defaultView.getSelection().toString());
      return false;
    }
  });
  $('#showUpBody').on("contextmenu", function (event) {
    return false;
  });
  ref2 = popData.engines;
  for (l = 0, len2 = ref2.length; l < len2; l++) {
    engine = ref2[l];
    $icon = $("#" + engine.id + "Icon");
    if (!GetOpt(engine.id)) {
      $icon.hide();
    }
  }
  $DivBox.find('.userEngine').on('click', OnEngine); // handle user engine!
  if (GetOpt('Tab_st')) {
    $DivBox.find('a').attr('target', '_blank');
  } else {
    $DivBox.find('a').attr('target', '_self');
  }
  if (GetOpt('Dis_st')) {
    popData.tip = popData.tipUp;
    return $DivBox.append('<span id="popupTip" class="tipUp"></span>');
  } else {
    popData.tip = popData.tipDown;
    return $DivBox.prepend('<span id="popupTip" class="tipDown"></span>');
  }
};

ajaxError = function (res) {
  return $('#transPanel').empty().append(`<p>Translate Error:<br /> ${res.statusText} </p>`).show();
};

onCopy = function () {
  CopyText();
  return hideBar();
};

onTranslate = function (engine) {
  popData.bTrans = 1;
  $("#transPanel").empty().append(`<div style='padding:10px;'><img src='${popData.icons.pending}' /></div>`).show();
  $('#popupWrapper').hide();
  fixPos(document.defaultView.getSelection());
  return doRequest(engine, 0, 2000);
};

doRequest = function (engine, i, wait) {
  var ErrHandle, lang;
  ErrHandle = function () {
    return doRequest(engine, i + 1, wait + 2000);
  };
  if (i >= 2) {
    ErrHandle = ajaxError;
  }
  lang = navigator.language || navigator.userLanguage || "zh-CN";
  if (engine === 'google') {
    return GM_xmlhttpRequest({
      method: 'POST',
      url: `https://translate.google.com/translate_a/single?client=gtx&dj=1&q=${popData.text}&sl=auto&tl=${lang}&hl=${lang}&ie=UTF-8&oe=UTF-8&source=icon&dt=t&dt=bd`,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        "Accept-Encoding": "gzip, deflate"
      },
      timeout: wait,
      onload: parseTranslationGoogle,
      onerror: ErrHandle,
      ontimeout: ErrHandle
    });
  } else if (engine === 'deepl') {
    return GM_xmlhttpRequest({
      method: 'POST',
      url: "https://api-free.deepl.com/v2/translate??auth_key=aa09f88d-ab75-3488-b8a3-18ad27a35870:fx",
      data: "auth_key=aa09f88d-ab75-3488-b8a3-18ad27a35870:fx&target_lang=ZH&text=" + popData.text,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      timeout: wait,
      onload: parseTranslationDeepl,
      onerror: ErrHandle,
      ontimeout: ErrHandle
    });
  } else {
    return GM_xmlhttpRequest({
      method: 'POST',
      url: "http://api.interpreter.caiyunai.com/v1/translator",
      headers: {
        'Content-Type': 'application/json',
        "X-Authorization": "token " + "3975l6lr5pcbvidl6jl2"
      },
      data: JSON.stringify({
        "source": [popData.text],
        "trans_type": "auto2zh",
        "request_id": "demo",
        "detect": true
      }),
      timeout: wait,
      onload: parseTranslationCaiyun,
      onerror: ErrHandle,
      ontimeout: ErrHandle
    });
  }
};

parseTranslationDeepl = function (responseDetails) {
  var RTxt, Result;
  if (!popData.bTrans) {
    return;
  }
  try {
    RTxt = JSON.parse(responseDetails.responseText);
  } catch (error) {
    log(JSON.stringify(responseDetails));
    return ajaxError(responseDetails);
  }
  Result = `<div id=\"tranRst\" style=\"font-size:13px;overflow:auto;padding:5px 12px;\"> <div style=\"line-height:200%;font-size:13px;\"> ${RTxt.translations[0].text} </div> </div>`;
  $('#transPanel').empty().append(Result).show();
  fixPos(document.defaultView.getSelection());
};

parseTranslationCaiyun = function (responseDetails) {
  var RTxt, Result;
  if (!popData.bTrans) {
    return;
  }
  try {
    RTxt = JSON.parse(responseDetails.responseText);
    log(JSON.stringify(RTxt));
  } catch (error) {
    return ajaxError(responseDetails);
  }
  Result = `<div id=\"tranRst\" style=\"font-size:13px;overflow:auto;padding:5px 12px;\"> <div style=\"line-height:200%;font-size:13px;\"> ${RTxt.target[0]} </div> </div>`;
  $('#transPanel').empty().append(Result).show();
  fixPos(document.defaultView.getSelection());
};

parseTranslationGoogle = function (responseDetails) {
  var PickMeaning, RLine, RTxt, Result, j, len, line, ref, sentence;
  if (!popData.bTrans) {
    return;
  }
  try {
    RTxt = JSON.parse(responseDetails.responseText);
  } catch (error) {
    return ajaxError(responseDetails);
  }
  RLine = function () {
    var j, len, ref, results;
    ref = RTxt.sentences;
    results = [];
    for (j = 0, len = ref.length; j < len; j++) {
      sentence = ref[j];
      results.push(sentence.trans);
    }
    return results;
  }().toString();
  PickMeaning = function (list) {
    var i, item, j, len, results;
    results = [];
    for (i = j = 0, len = list.length; j < len; i = ++j) {
      item = list[i];
      if (item.score > 0.005 || i < 3) {
        results.push(item.word);
      }
    }
    return results;
  };
  if (RTxt.dict != null) {
    ref = RTxt.dict;
    for (j = 0, len = ref.length; j < len; j++) {
      line = ref[j];
      RLine += "<br>" + `${line.pos} : ${PickMeaning(line.entry)}`;
    }
  }
  Result = `<div id=\"tranRst\" style=\"font-size:13px;overflow:auto;padding:5px 12px;\"> <div style=\"line-height:200%;font-size:13px;\"> ${RLine} </div> </div>`;
  $('#transPanel').empty().append(Result).show();
  fixPos(document.defaultView.getSelection());
};

doHideBar = function () {
  return $('#ShowUpBox').fadeOut(150);
};

hideBar = function (time = 0) {
  return popData.fadeEvent.push(setTimeout(doHideBar, time));
};

$(document).on("mousedown", function (event) {
  popData.mousedownEvent = event;
  hideBar();
  if (popData.bTrans === 1) {
    return PopupInit();
  }
});

$(document).on("mouseup", function (event) {
  // PopupInit() if popData.bTrans == 1
  // hideBar() if not GetOpt('Click_st')
  if (event.which !== 1) {
    return;
  }
  if (GetOpt('Ctrl_st') && !event.ctrlKey) {
    return;
  }
  return ShowBar(event);
});

$(document).on("keydown", function (event) {
  if (event.key === "Escape") {
    if ($('#ShowUpBox').is(":visible")) {
      hideBar();
      event.stopPropagation();
      return False;
    }
  }
  if (event.ctrlKey && event.altKey && event.key === "p") {
    return ShowBar();
  }
});

eventFromTextbox = function (eventList) {
  var event, j, len;
  for (j = 0, len = eventList.length; j < len; j++) {
    event = eventList[j];
    if (event != null) {
      if ($(event.target).is('textarea, input, *[contenteditable="true"]')) {
        //console.log $(event.target)
        return true;
      }
    }
  }
  return false;
};

InTextBox = function (selection) {
  var area, j, len, ref;
  if (isChrome()) {
    return false;
  }
  ref = $('textarea, input, *[contenteditable="true"]', document);
  for (j = 0, len = ref.length; j < len; j++) {
    area = ref[j];
    if (selection.containsNode(area, true)) {
      return true;
    }
  }
  return false;
};

GetTextboxSelection = function () {
  var textbox;
  textbox = document.activeElement;
  if (textbox.selectionEnd - textbox.selectionStart > 0) {
    return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd);
  }
  return "";
};

OpenUrl = function (link) {
  if (isChrome()) {
    //log "chrome"
    return GM_openInTab(link, {
      active: GetOpt("Focus_st") === 1
    });
  } else {
    return GM_openInTab(link, !GetOpt("Focus_st"));
  }
};

OnEngine = function (e) {
  var link;
  link = $(this).data('link');
  if (link.indexOf('javascript:') === 0) {
    eval(link.slice('javascript:'.length));
    return false;
  }
  OpenUrl(link);
  hideBar(100);
  return false;
};

ShowBar = function (event) {
  var do_timeout_hide, e, engine, j, k, l, len, len1, len2, paraList, ref, ref1, ref2, sel, setHref;
  hideBar();
  sel = document.defaultView.getSelection();
  if (InTextBox(sel) || eventFromTextbox([event, popData.mousedownEvent])) {
    popData.rawText = GetTextboxSelection().trim();
  } else {
    popData.rawText = sel.toString().trim();
  }
  if (GetOpt("AutoCopy_st")) {
    if (InTextBox(sel) || eventFromTextbox([event, popData.mousedownEvent])) {
      if (GetOpt("AutoCopy_tbox_st")) {
        // none text areas?
        CopyText(popData.rawText);
      }
    } else {
      CopyText(popData.rawText);
    }
  }
  popData.text = encodeURIComponent(popData.rawText);
  if (popData.rawText === '') {
    return;
  }
  if (InTextBox(sel) || eventFromTextbox([event, popData.mousedownEvent])) {
    if (GetOpt("Textbox_st")) {
      return;
    }
  }
  ref = popData.fadeEvent;
  // we have hide event for every mousedown
  for (j = 0, len = ref.length; j < len; j++) {
    e = ref[j];
    clearTimeout(e);
  }
  $('#transPanel').empty().hide();
  paraList = {
    "\\${rawText}": popData.rawText,
    "\\${text}": popData.text,
    "\\${domain}": document.domain,
    "\\${url}": location.href
  };
  setHref = function (engine) {
    var $engine, href, para, runFunction, value;
    $engine = $("#" + engine.id + "Icon");
    if (engine.href != null) {
      href = engine.href;
      for (para in paraList) {
        if (!hasProp.call(paraList, para)) continue;
        value = paraList[para];
        href = href.replace(RegExp(`${para}`, "g"), value);
      }
      $engine.data('link', href);
      $engine.off('click');
      return $engine.on('click', OnEngine);
    } else if (engine.action != null) {
      $engine.off('click');
      return $engine.on('click', engine.action);
    } else if (engine.function != null) {
      log("func " + engine.id + " : " + engine.function);
      runFunction = function (func) {
        console.log(popData.rawText, popData.text, document.domain, location.url);
        return Function('"use strict";return (' + func + ')')()(popData.rawText, popData.text, document.domain, location.url, OpenUrl);
      };
      $engine.off('click');
      return $engine.on('click', function () {
        // func.apply(null, [popData.rawText, popData.text, popData.domain, popData.url])
        runFunction("function action(rawText, text, domain, url, OpenUrl) {" + engine.function + "}");
        hideBar(100);
        return false;
      });
    } else {
      return console.log('empty engine', engine);
    }
  };
  ref1 = popData.engines;
  for (k = 0, len1 = ref1.length; k < len1; k++) {
    engine = ref1[k];
    setHref(engine);
  }
  ref2 = popData.userEngines;
  for (l = 0, len2 = ref2.length; l < len2; l++) {
    engine = ref2[l];
    setHref(engine);
  }
  if (needPrefix(popData.rawText)) {
    $('#Open_stIcon').data('link', `http://${popData.rawText}`);
  }
  popData.mouseIn = 0;
  popData.bTrans = 0;
  do_timeout_hide = function () {
    if (popData.mouseIn === 0 && !popData.bTrans) {
      return $('#ShowUpBox').fadeOut(250);
    }
  };
  if (GetOpt("Fade_st")) {
    popData.fadeEvent.push(setTimeout(do_timeout_hide, 5000));
  }
  fixPos(sel, event);
  return $('#ShowUpBox').css('opacity', 0.9).fadeIn(200);
};

needPrefix = function (url) {
  var j, len, prefix, urlPrefixes;
  url = url.trim();
  urlPrefixes = ['http://', 'https://', 'ftp://', 'file://', 'thunder://', 'ed2k://', 'chrome://'];
  for (j = 0, len = urlPrefixes.length; j < len; j++) {
    prefix = urlPrefixes[j];
    if (url.indexOf(prefix) === 0) {
      return 0;
    }
  }
  return 1;
};

CopyText = function (selText) {
  var e;
  if (selText == null) {
    selText = popData.rawText;
  }
  if (selText === '') {
    return;
  }
  if ((typeof GM_info !== "undefined" && GM_info !== null ? GM_info.scriptHandler : void 0) === "Violentmonkey") {
    return document.execCommand('copy');
  }
  try {
    return GM_setClipboard(selText, "text");
  } catch (error) {
    e = error;
    console.log(e);
    return document.execCommand('copy');
  }
};

GetOpt = function (id) {
  var ref;
  return GM_getValue(id, (ref = popData.optionList.find(function (item) {
    return item.id === id;
  })) != null ? ref.defaultValue : void 0);
};

SaveOpt = function (id) {
  return GM_setValue(id, $("#" + id + " > input").prop("checked") + 0);
};

ReadOpt = function (id) {
  return $("#" + id + " > input").prop("checked", GetOpt(id));
};

OpenSet = function () {
  if ($('#popup_setting_bg').length === 0) {
    SettingWin();
  }
  return $('#popup_setting_bg').fadeIn(400);
};

SettingWin = function () {
  var engine, engineOptionList, exampleJSON, generateEngineOption, generateOption, item, j, len, option, optionList, ref;
  addAdditionalCSS();
  $('#popup_setting_bg').remove();
  generateOption = function (option) {
    return `<span id='${option.id}' class='setting_item'> <img src=${popData.icons.settingIcon} /> <span class='text'>${option.text}</span> <input class='tgl tgl-flat' id='${option.id}_checkbox' type='checkbox'> <label class='tgl-btn' for='${option.id}_checkbox'></label> </span>`;
  };
  optionList = function () {
    var j, len, ref, results;
    ref = popData.optionList;
    results = [];
    for (j = 0, len = ref.length; j < len; j++) {
      option = ref[j];
      results.push(generateOption(option));
    }
    return results;
  }().join(' ');
  generateEngineOption = function (engine) {
    return `<span id='${engine.id}' class='setting_item'> <img src=${engine.src} /> <span class='text'>${engine.description}</span> <input class='tgl tgl-flat' id='${engine.id}_checkbox' type='checkbox'> <label class='tgl-btn' for='${engine.id}_checkbox'></label> </span>`;
  };
  engineOptionList = function () {
    var j, len, ref, results;
    ref = popData.engines;
    results = [];
    for (j = 0, len = ref.length; j < len; j++) {
      engine = ref[j];
      results.push(generateEngineOption(engine));
    }
    return results;
  }().join(' ');
  exampleJSON = JSON.stringify(popData.defaultEngines, null, 4);
  $("body").append(`<div id='popup_setting_bg'> <div id='popup_setting_win'> <div id='popup_title'>PopUp Search Setting</div> <div id='popup_content'> <div id='tabs_box'> <div id='popup_tab1' class='popup_tab popup_selected'>选项 / General</div> <div id='popup_tab2' class='popup_tab'>搜索引擎 / Engines</div> <div id='popup_tab3' class='popup_tab'>自定义 / Customize</div> <div id='popup_tab4' class='popup_tab'>关于 / About</div> </div> <div id='page_box'> <div id='option_box'> <div id='popup_tab1Page'> ${optionList} </div> <div id='popup_tab2Page'> ${engineOptionList} </div> <div id='popup_tab3Page'> <div id='editTitle'> <div><b>请阅读帮助! / Read help FRIST !</b></div> <span id='popHelp'><u>Help</u></span> <span id='popReset'><u>Reset</u></span> </div> <textarea id='popup_engines'></textarea> <textarea id='popup_engines_placehold'></textarea> </div> <div id='popup_tab4Page'> <h3>Authored by Lkytal</h3> <p> You can redistribute it under <a href='http://creativecommons.org/licenses/by-nc-sa/4.0/'> Creative Commons Attribution-NonCommercial-ShareAlike Licence </a> </p> <p class='contact-line'> Source Code at<br> Git OSChina <a class='tab-text' href='https://git.oschina.net/coldfire/GM'> https://git.oschina.net/coldfire/GM </a> <br /> Github <a class='tab-text' href='https://github.com/lkytal/GM'> https://github.com/lkytal/GM </a> </p> <p> Contact:<br> Github <a class='tab-text' href='https://github.com/lkytal'> https://github.com/lkytal/ </a> <br> Greasy fork <a class='tab-text' href='https://greasyfork.org/en/users/152-lkytal'> https://greasyfork.org/en/users/152-lkytal </a> </p> </div> </div> <div id='btnArea'> <div id='popup_save' class='setting_btn'>Save</div> <div id='popup_close' class='setting_btn'>Close</div> </div> </div> </div> </div> <div id='popup_help_bg'> <div id='popup_help_win'> <div id='popup_help_content'> <div id='helpLang'> <span id='engHead' class='popup_head_selected'>English</span> <span id='chsHead'>中文</span> </div> <div id='help_box'> <div id='engContent'> The content of custom engine should be in standard JSON format, in forms of following: <pre> ${exampleJSON} </pre> The 'id' should be unique for every entry and must NOT contain any space character, the 'title' and the 'description' can be any text you like, the 'src' indicates the icon of every item, should be the URL to an image or be a <a href='http://dataurl.net/#about'>DataURL</a>. The 'href' is the link to be open upon click, you may have noticed the '\${text}' variable, which will be replaced by selected text. Available variables are listed below: <ul> <li>\${text} : will be replaced by the selected text (Url encoded, should use this by default)</li> <li>\${rawText} : will be replaced by the original selected text</li> <li>\${domain} : will be replaced by the domain of current URL</li> <li>\${url} : will be replaced by the current web page's URL</li> </ul> When using 'function' style, all above variable is usable. Besides, you can directly call 'OpenUrl' to open a link. Note: You can't modify built-in engines directly, however, you can disable them and add your own. </div> <div id='chsContent'> 自定义引擎内容应当是合法的JSON格式, 如下 <pre> ${exampleJSON} </pre> 每一项的 id 必须各不相同且不能含有空格, title 和 description 可以随意填写, src 是该项的图标, 可以是指向图标的 url 或者是一个 <a href='http://dataurl.net/#about'>DataURL</a>. href 是引擎的 url 链接, 其中可以包含诸如 \${text} 这样的变量, 变量的大小写必须正确, 可用的变量有: <ul> <li>\${text} : 代表选中文字, 经过 url encoding, 一般应当使用此项</li> <li>\${rawText} : 代表未经 encoding 的原始选中文字</li> <li>\${domain} : 代表当前页面的域名</li> <li>\${url} : 代表当前页面的 url 地址</li> </ul> 当使用function的时候, 以上变量都可以直接调用. 此外, 可以直接调用OpenUrl函数来打开新链接 注意: 内置引擎无法直接修改, 你可以禁用它们然后添加你自定义的引擎 </div> </div> <div id='help_btnArea'> <div id='popup_help_close' class='setting_btn'>Close</div> </div> </div> </div> </div> </div>`);
  $("#popup_setting_bg, #popup_help_bg").hide();
  $("#tabs_box > .popup_tab").on("click", function (e) {
    $("#tabs_box > .popup_tab").removeClass("popup_selected");
    $(this).addClass("popup_selected");
    $("#option_box > div").hide();
    return $("#" + $(this).attr("id") + "Page").show();
  });
  $("#option_box > div").hide();
  $("#tabs_box > .popup_tab.popup_selected").click();
  $("#chsContent").hide();
  $("#engHead").on('click', function (event) {
    $("#engHead").addClass("popup_head_selected");
    $("#chsHead").removeClass("popup_head_selected");
    $("#engContent").show();
    return $("#chsContent").hide();
  });
  $("#chsHead").on('click', function (event) {
    $("#engHead").removeClass("popup_head_selected");
    $("#chsHead").addClass("popup_head_selected");
    $("#engContent").hide();
    return $("#chsContent").show();
  });
  ref = $("#popup_setting_win .setting_item");
  for (j = 0, len = ref.length; j < len; j++) {
    item = ref[j];
    if (item != null) {
      ReadOpt(item.id);
    }
  }
  $("#popReset").click(function () {
    if (confirm("Reset?")) {
      return $("#popup_engines").val(popData.defaultEngineString);
    }
  });
  $("#popHelp").click(function () {
    return $("#popup_help_bg").fadeIn();
  });
  $("#popup_engines").val(GM_getValue("engineString", popData.defaultEngineString));
  if (GetOpt("userEngine_st")) {
    $("#popup_engines").show();
    $("#popup_engines_placehold").hide();
  } else {
    $("#popup_engines").hide();
    $("#popup_engines_placehold").show();
    $("#popup_engines_placehold").attr('disabled', true);
    $("#popup_engines_placehold").val(`Disabled, please enable custom engines in setting,
then save and re-open this setting page\n
已禁用, 请在设置启用自定义引擎, 保存并重新打开此界面`);
  }
  $("#popup_save").click(function () {
    var k, len1, ref1, userEngineString;
    ref1 = $("#popup_setting_win .setting_item");
    for (k = 0, len1 = ref1.length; k < len1; k++) {
      item = ref1[k];
      if (item != null) {
        SaveOpt(item.id);
      }
    }
    if (GetOpt("userEngine_st")) {
      userEngineString = $("#popup_engines").val();
      if (userEngineString !== "") {
        try {
          popData.userEngines = JSON.parse(userEngineString);
          GM_setValue("engineString", userEngineString);
        } catch (error) {
          alert("自定义引擎错误! 请检查\nEngine config Error!");
          log(userEngineString);
        }
      }
    }
    return $("#popup_setting_bg").fadeOut(300, function () {
      $("#popup_setting_bg").remove(); //force rebuild setting window
      return PopupInit(); //rebuild toolbar
    });
  });
  $("#popup_close, #popup_setting_bg").click(function () {
    return $("#popup_setting_bg").fadeOut(300, function () {
      return $("#popup_setting_bg").remove();
    });
  });
  $("#popup_help_bg, #popup_help_close").on("click", function (e) {
    return $("#popup_help_bg").fadeOut();
  });
  return $('#popup_setting_win, #popup_help_win, #popup_help_bg').click(function (e) {
    return e.stopPropagation();
  });
};

UpdateLog = function () {
  addAdditionalCSS();
  $("body").append("<div id='popup_update_bg'> <div id='popup_update_win'> <div id='update_header'> Popup Search Updated (ver 4.3.0) </div> <div id='popup_update_content'> <div id='update_texts'> <p> <h3>此版本引入的重要改变:</h3> <p> 增加了复制按钮 </p> <p> 自定义引擎功能开放, 点击 'Open setting' 可以打开设置并启用该功能. 在自定义前请点击 'Help' 按钮以阅读帮助文档. </p> <p> 注意: 启用自定义引擎后, 重新打开设置窗口才会生效. </p> </p> <p> <h3>What's new in this version:</h3> <p> Provide 'Copy' button </p> <p> You can customize your own engines now. Click 'Open setting' to check it out. Remember to read 'HELP' before modify. </p> <p> Note: After you enabled customization, reopen setting window to take effect. </p> </p> </div> <div id='update_btnArea'> <div id='popup_update_open' class='setting_btn'>Open Setting</div> <div id='popup_update_close' class='setting_btn'>Close</div> </div> </div> </div> </div>");
  $('#popup_update_open').on('click', function (event) {
    UpdateNotified();
    $("#popup_update_bg").hide();
    OpenSet();
  });
  return $('#popup_update_close').on('click', function (event) {
    UpdateNotified();
    $("#popup_update_bg").hide();
  });
};

UpdateNotified = function () {
  return GM_setValue("UpdateAlert", popData.codeVersion);
};

PopupLoad = function () {
  var engine, j, k, len, len1, option, popupMenu, ref, ref1, setDefault, userEngineString;
  if (window.self !== window.top || window.frameElement) {
    if (!GM_getValue("Iframe_st", 0)) {
      return;
    }
  }
  addCSS();
  if (GM_getValue("UpdateAlert", 0) < popData.codeVersion) {
    setDefault = function (key, defaultValue) {
      return GM_setValue(key, GM_getValue(key, defaultValue));
    };
    ref = popData.optionList;
    for (j = 0, len = ref.length; j < len; j++) {
      option = ref[j];
      setDefault(option.id, option.defaultValue);
    }
    ref1 = popData.engines;
    for (k = 0, len1 = ref1.length; k < len1; k++) {
      engine = ref1[k];
      setDefault(engine.id, engine.defaultState);
    }
    UpdateLog();
  }
  popData.defaultEngineString = JSON.stringify(popData.defaultEngines, null, 4);
  if (GetOpt("userEngine_st")) {
    userEngineString = GM_getValue("engineString", popData.defaultEngineString);
    try {
      popData.userEngines = JSON.parse(userEngineString);
    } catch (error) {
      //alert "User Engine Syntax Error"
      console.error(userEngineString);
    }
  }
  PopupInit();
  GM_registerMenuCommand("Popup Search Setting / 设置", OpenSet, 'p');
  if (GM_getValue("PopupMenu", 0)) {
    popupMenu = document.body.appendChild(document.createElement("menu"));
    popupMenu.outerHTML = '<menu id="userscript-popup" type="context"><menuitem id="PopupSet" label="Popup Search设置"></menuitem></menu>';
    document.querySelector("#PopupSet").addEventListener("click", OpenSet, false);
    return $(document).on("contextmenu", function () {
      return document.body.setAttribute("contextmenu", "userscript-popup");
    });
  }
};

setTimeout(PopupLoad, 100);

addCSS = function () {
  return GM_addStyle(`#ShowUpBox { width: auto; height: auto; position: absolute; z-index: 99900000000; color: black; display: inline-block; line-height: 0; vertical-align: baseline; box-sizing: content-box; font-size: 16px; } #showUpBody { min-width: 20px; max-width: 750px; min-height: 20px; max-height: 500px; display: block; border: solid 2px rgb(144,144,144); border-radius: 1px; background: rgba(252, 252, 252, 1); } #popupWrapper { margin: 3px 2px 3.8px 2px; display:block; line-height: 0; font-size:0; } #transPanel { line-height: normal; width: auto; font-size: 16px; overflow: auto; display: none; } #popupWrapper > a { margin: 0px 2px; } #popupWrapper img { margin: 0px; height: 24px; width: 24px; border-radius: 0px; padding: 0px; display: inline-block; transition-duration: 0.1s; -moz-transition-duration: 0.1s; -webkit-transition-duration: 0.1s; } #popupWrapper img:hover { margin: -1px -1px; height: 26px; width: 26px; } #popupTip { display: inline-block; clear: both; height: 9px; width: 9px; } .tipUp { background: url(${popData.icons.tipUp}) 0px 0px no-repeat transparent; margin-top: -2px; margin-bottom: 0px; } .tipDown { background: url(${popData.icons.tipDown}) 0px 0px no-repeat transparent; margin-top: 0px; margin-bottom: -2px; } #ShowUpBox a { text-decoration: none; display: inline-block; }`);
};

addAdditionalCSS = function () {
  if (popData.additionalCSSLoaded === 1) {
    return;
  }
  popData.additionalCSSLoaded = 1;
  return GM_addStyle("#popup_setting_bg { width: 100%; height: 100%; background: rgba(0, 0, 0, 0.2); position: fixed; left: 0px; top: 0px; z-index:102400; font-family: \"Hiragino Sans GB\", \"Microsoft Yahei\", Arial, sans-serif; display: -webkit-flex; display: flex; justify-content: center; align-items: center; } #popup_setting_win { font-size: 16px; width: 760px; height: 90%; box-shadow: 0 0 10px #222; box-sizing: content-box !important; background: rgba(255, 255, 255, 0.98); overflow: hidden; display: -webkit-flex; display: -moz-flex; display: flex; flex-direction: column; } #popup_title { font-size: 22px; font-weight: bold; text-align: center; padding: 12px; background: #16A085; color: white; flex-shrink: 0; } #popup_content { flex-grow: 1; flex-shrink: 1; height: calc(100% - 70px); padding: 0px; display: -webkit-flex; display: -moz-flex; display: flex; justify-content: space-between; align-items: stretch; } #tabs_box { display: -webkit-flex; display: -moz-flex; display: flex; flex-direction: column; flex-basis: 25%; flex-shrink: 0; background: #EEE; } .popup_tab { width: 100%; background: #EEE; padding: 15px; font-weight: bold; text-align: center; box-sizing: border-box; cursor: pointer; user-select: none; -moz-user-select: none; -webkit-user-select: none; } .popup_tab:hover { background: #ccc; } .popup_selected { border-right: none; background: #FFF; } .popup_selected:hover { background: #FFF; } #page_box { padding: 20px 30px; flex-grow: 1; flex-shrink: 1; max-height: 100%; display: -webkit-flex; display: -moz-flex; display: flex; flex-direction: column; } #option_box { display: -webkit-flex; display: -moz-flex; display: flex; flex-direction: column; align-items: stretch; flex-grow: 1; flex-shrink: 1; overflow-y: auto; } #option_box > div { scroll-behavior: smooth; flex-grow: 1; display: -webkit-flex; display: -moz-flex; display: flex; flex-direction: column; align-items: stretch; } #popup_engines, #popup_engines_placehold { flex-grow: 1; border: solid 2px #ddd; text-overflow: clip; white-space: pre; overflow-x: auto; overflow-y: auto; word-wrap: break-word; resize: none; } #editTitle { padding: 0px 0px 15px 0px; display: -webkit-flex; display: -moz-flex; display: flex; justify-content: space-between; } #editTitle div { flex-grow: 1; } #editTitle span { margin-left: 20px; color : #1ABC9C; cursor: pointer; } #btnArea { display: -webkit-flex; display: -moz-flex; display: flex; justify-content: flex-end; margin-top: 20px; flex-shrink: 0; } .setting_btn { display: inline-block; font-size: 16px; text-align: center; mix-width: 50px; padding: 4px 10px 4px 10px; border-radius: 2px; margin: 0px 0px 0px 20px; background: #1ABC9C; color: #fff; cursor: pointer; user-select: none; -moz-user-select: none; -webkit-user-select: none; } .setting_btn:hover { text-shadow: 0px 0px 2px #FFF; } .setting_item { min-height: 24px; font-size: 14px; margin: 5px 0px 10px 0px; display: -webkit-flex; display: -moz-flex; display: flex; align-items: center; } .setting_item > img { width: 24px; height: auto; margin-right: 7px; } .setting_item .text{ flex-grow: 1; font-size: 14px; } #popup_help_bg { all: unset; width: 100%; height: 100%; position: fixed; top: 0; left: 0; background: transparent; display: -webkit-flex; display: flex; justify-content: center; align-items: center; z-index: 10240000; } #popup_help_win { font-size: 16px; all: unset; width: 650px; height: 80%; box-shadow: 0 0 10px #222; box-sizing: content-box !important; background: rgba(255, 255, 255, 0.98); padding: 20px; display: -webkit-flex; display: flex; flex-direction: column; align-items: stretch; /*overflow: hidden;*/ } #popup_help_content { max-height: 100%; flex-grow: 1; display: -webkit-flex; display: flex; flex-direction: column; align-items: stretch; } #helpLang { flex-grow: 0; flex-shrink: 0; display: -webkit-flex; display: flex; border-bottom: solid 1px #ccc; } #helpLang span { padding: 8px 30px; margin-bottom: -1px; cursor: pointer; user-select: none; -moz-user-select: none; -webkit-user-select: none; } #helpLang span.popup_head_selected { border-top: solid 1px #ccc; border-left: solid 1px #ccc; border-right: solid 1px #ccc; border-bottom: solid 3px #FFF; } #help_box { overflow-y: auto; flex-grow: 1; flex-shrink: 1; margin-top: 15px; } #help_box > div { word-wrap: break-word; } #help_btnArea { flex-grow: 0; flex-shrink: 0; display: -webkit-flex; display: flex; justify-content: flex-end; margin-top: 20px; } #popup_update_bg { all: unset; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.2); position: fixed; left: 0px; top: 0px; z-index: 1024000; font-family: \"Hiragino Sans GB\", \"Microsoft Yahei\", Arial, sans-serif; display: -webkit-flex; display: flex; justify-content: center; align-items: center; } #popup_update_win { all: unset; width: 50%; height: 80%; box-shadow:0 0 10px #222; box-sizing: content-box !important; background: rgba(255, 255, 255, 0.98); overflow: hidden; font-size: 16px; display: -webkit-flex; display: -moz-flex; display: flex; flex-direction: column; } #update_header { font-size: 24px; font-weight: bold; text-align: center; padding: 15px; background: #16A085; color: white; flex-shrink: 0; height: 40px; } #popup_update_content { flex-grow: 1; flex-shrink: 1; height: calc(100% - 70px); overflow: auto; padding: 15px; display: -webkit-flex; display: -moz-flex; display: flex; flex-direction: column; justify-content: space-between; align-items: stretch; } #update_texts{ flex-grow: 1; flex-shrink: 1; } #update_btnArea { flex-grow: 0; flex-shrink: 0; display: -webkit-flex; display: flex; justify-content: flex-end; margin-top: 20px; } .hidden { display: none; } .tgl { display: none; } .tgl, .tgl:after, .tgl:before, .tgl *, .tgl *:after, .tgl *:before, .tgl+.tgl-btn { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .tgl::-moz-selection, .tgl:after::-moz-selection, .tgl:before::-moz-selection, .tgl *::-moz-selection, .tgl *:after::-moz-selection, .tgl *:before::-moz-selection, .tgl+.tgl-btn::-moz-selection { background: none; } .tgl::selection, .tgl:after::selection, .tgl:before::selection, .tgl *::selection, .tgl *:after::selection, .tgl *:before::selection, .tgl+.tgl-btn::selection { background: none; } .tgl+.tgl-btn { outline: 0; display: inline-block; width: 4em; height: 2em; position: relative; cursor: pointer; } .tgl+.tgl-btn:after, .tgl+.tgl-btn:before { position: relative; display: inline-block; content: \"\"; width: 50%; height: 100%; } .tgl+.tgl-btn:after { left: 0; } .tgl+.tgl-btn:before { display: none; } .tgl:checked+.tgl-btn:after { left: 50%; } .tgl-flat+.tgl-btn { padding: 2px; -webkit-transition: all .2s ease; transition: all .2s ease; background: #fff; border: 3px solid #f2f2f2; border-radius: 0.5em; } .tgl-flat+.tgl-btn:after { -webkit-transition: all .2s ease; transition: all .2s ease; background: #f2f2f2; content: \"\"; border-radius: 0.25em; } .tgl-flat:checked+.tgl-btn { border: 3px solid #1ABC9C; } .tgl-flat:checked+.tgl-btn:after { left: 50%; background: #1ABC9C; }");
};

getLastRange = function (selection) {
  var j, rangeNum, ref;
  for (rangeNum = j = ref = selection.rangeCount - 1; ref <= 0 ? j <= 0 : j >= 0; rangeNum = ref <= 0 ? ++j : --j) {
    if (!selection.getRangeAt(rangeNum).collapsed) {
      return selection.getRangeAt(rangeNum);
    }
  }
  return selection.getRangeAt(selection.rangeCount - 1);
};

get_selection_offsets = function (selection, e) {
  var $test_span, Rect, lastRange, newRange;
  try {
    $test_span = $('<span style="display:inline;">x</span>');
    // "x" because it must have a height
    lastRange = getLastRange(selection);
    newRange = document.createRange();
    newRange.setStart(lastRange.endContainer, lastRange.endOffset);
    newRange.insertNode($test_span[0]);
    Rect = $test_span[0].getBoundingClientRect();
    $test_span.remove();
    return [Rect.top + window.scrollY, Rect.left + window.scrollX, 0, 0];
  } catch (error) {
    return [e.pageY, e.pageX, 0, 0];
  }
};